package com.pz.cloud.framework.workflow.service.impl;

import com.pz.cloud.framework.base.expection.CustomRuntimeException;
import com.pz.cloud.framework.business.workflow.entity.WaitDone;
import com.pz.cloud.framework.business.workflow.service.IWaitDoneService;
import com.pz.cloud.framework.business.workflow.service.IWaitDoneUserService;
import com.pz.cloud.framework.business.workflow.service.IWorkflowService;
import com.pz.cloud.framework.business.workflow.service.IWorkflowTaskService;
import com.pz.cloud.framework.util.BizUtil;
import com.pz.cloud.framework.util.SqlUtil;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.util.*;


/**
 * 工作流服务
 * @author mazezhan
 */
@Transactional(rollbackFor = Exception.class)
@Service
public class WorkflowTaskServiceImpl implements IWorkflowTaskService {
    @Autowired
    private ProcessEngine processEngine;
    @Autowired
    protected IWaitDoneService waitDoneService;
    @Autowired
    protected IWorkflowService workflowService;
    @Autowired
    protected IWaitDoneUserService waitDoneUserService;
    @PersistenceContext
    protected EntityManager entityManager;

    private void execute(String sql,Map<String,Object>parms){
        Query query = entityManager.createNativeQuery(sql);
        if(parms!=null&&parms.size()>0){
            SqlUtil.setQueryParams(parms,query);
        }
        query.executeUpdate();
    }
    /**
     * 流程备份操作
     * @param taskId
     * @return
     */
    public void backupTask(String taskId) {
        Task task = processEngine.getTaskService().createTaskQuery().taskId(taskId).singleResult();
        if(task==null){
            throw new CustomRuntimeException("任务不存在！");
        }
        String proInstanceId = task.getProcessInstanceId();
        Map parms = new HashMap();
        /**
         * 第一步  删除所有当前任务的备份表数据
         */
        List<String> deleteBackupSql = Arrays.asList(
                "delete from backup_taskIds where BACKUP_TASK_ID_ = :taskId ",
                "delete from backup_ru_execution where BACKUP_TASK_ID_ = :taskId ",
                "delete from backup_hi_varinst where BACKUP_TASK_ID_ = :taskId ",
                "delete from backup_hi_taskinst where BACKUP_TASK_ID_ = :taskId ",
                "delete from backup_hi_identitylink where BACKUP_TASK_ID_ = :taskId ",
                "delete from backup_ru_identitylink where BACKUP_TASK_ID_ = :taskId ",
                "delete from backup_hi_actinst where BACKUP_TASK_ID_ = :taskId ",
                "delete from backup_ru_variable where BACKUP_TASK_ID_ = :taskId ",
                "delete from backup_ru_task where BACKUP_TASK_ID_ = :taskId"
                );
        parms.clear();
        parms.put("taskId",taskId);
        for (String sql : deleteBackupSql) {
            execute(sql,parms);
        }
        /**
         *  第二步 更新所有备份任务状态为不可撤回
         */
        String updateBackupTaskSql = "update backup_taskIds set CAN_WITHDRAW = 0 where PROC_INST_ID_ = :proInstanceId";
        parms.clear();
        parms.put("proInstanceId",proInstanceId);
        execute(updateBackupTaskSql,parms);

        /**
         *第三步 标记当前任务为可撤回
         */
        parms.clear();
        parms.put("taskId",taskId);
        parms.put("proInstanceId",proInstanceId);
        String insertBackupTaskSql = "insert into backup_taskIds(BACKUP_TASK_ID_, PROC_INST_ID_, TASK_STATUS, CAN_WITHDRAW) VALUE(:taskId, :proInstanceId, 0, 1) ";
        execute(insertBackupTaskSql,parms);
        /**
         * 第四步，插入当前任务的备份表数据
         */
        /*备份处理人数据*/
        StringBuilder backup_ru_identitylink = new StringBuilder("insert into backup_ru_identitylink(ID_, REV_, GROUP_ID_, TYPE_, USER_ID_, TASK_ID_," )
                .append("  PROC_INST_ID_, PROC_DEF_ID_, BACKUP_TASK_ID_)")
                .append(" select ID_, REV_, GROUP_ID_, TYPE_, USER_ID_, TASK_ID_, :proInstanceId, PROC_DEF_ID_, :taskId")
                .append(" from act_ru_identitylink where TASK_ID_ = :taskId ");
        StringBuilder backup_hi_identitylink = new StringBuilder(   "insert into backup_hi_identitylink(ID_, GROUP_ID_, TYPE_, USER_ID_, TASK_ID_, PROC_INST_ID_, BACKUP_TASK_ID_)")
                .append(" select ID_, GROUP_ID_, TYPE_, USER_ID_, TASK_ID_, :proInstanceId, :taskId")
                .append(" from act_hi_identitylink where TASK_ID_ = :taskId");
        List<String> backupLinkSqlList = Arrays.asList(
                backup_ru_identitylink.toString(),
                backup_hi_identitylink.toString()
        );
        parms.clear();
        parms.put("proInstanceId",proInstanceId);
        parms.put("taskId",taskId);
        for (String sql : backupLinkSqlList) {
            execute(sql,parms);
        }
        /*备份任务数据*/
        StringBuilder backup_hi_actinst =new StringBuilder( "insert into backup_hi_actinst(ID_, PROC_DEF_ID_, PROC_INST_ID_, EXECUTION_ID_,")
                .append("  ACT_ID_, TASK_ID_, CALL_PROC_INST_ID_, ACT_NAME_,")
                .append(" ACT_TYPE_, ASSIGNEE_, START_TIME_, END_TIME_, DURATION_, DELETE_REASON_, TENANT_ID_, BACKUP_TASK_ID_)")
                .append(" select ID_, PROC_DEF_ID_, PROC_INST_ID_, EXECUTION_ID_, ACT_ID_, TASK_ID_, CALL_PROC_INST_ID_, ACT_NAME_,")
                .append("  ACT_TYPE_, ASSIGNEE_, START_TIME_, END_TIME_, DURATION_, DELETE_REASON_, TENANT_ID_, :taskId")
                .append(" from act_hi_actinst where PROC_INST_ID_ = :proInstanceId ");
        StringBuilder backup_ru_execution = new StringBuilder(  "insert into backup_ru_execution(ID_, REV_, PROC_INST_ID_, BUSINESS_KEY_,")
                 .append("  PARENT_ID_, PROC_DEF_ID_, SUPER_EXEC_,")
                .append("         ROOT_PROC_INST_ID_, ACT_ID_, IS_ACTIVE_, IS_CONCURRENT_, IS_SCOPE_, IS_EVENT_SCOPE_, IS_MI_ROOT_, SUSPENSION_STATE_,")
                .append("         CACHED_ENT_STATE_, TENANT_ID_, NAME_, START_TIME_, START_USER_ID_, LOCK_TIME_, IS_COUNT_ENABLED_, EVT_SUBSCR_COUNT_,")
                .append("         TASK_COUNT_, JOB_COUNT_, TIMER_JOB_COUNT_, SUSP_JOB_COUNT_, DEADLETTER_JOB_COUNT_, VAR_COUNT_, ID_LINK_COUNT_, BACKUP_TASK_ID_)")
                .append(" select ID_, REV_, PROC_INST_ID_, BUSINESS_KEY_, PARENT_ID_, PROC_DEF_ID_, SUPER_EXEC_,")
                .append("         ROOT_PROC_INST_ID_, ACT_ID_, IS_ACTIVE_, IS_CONCURRENT_, IS_SCOPE_, IS_EVENT_SCOPE_, IS_MI_ROOT_, SUSPENSION_STATE_,")
                .append("         CACHED_ENT_STATE_, TENANT_ID_, NAME_, START_TIME_, START_USER_ID_, LOCK_TIME_, IS_COUNT_ENABLED_, EVT_SUBSCR_COUNT_,")
                .append("         TASK_COUNT_, JOB_COUNT_, TIMER_JOB_COUNT_, SUSP_JOB_COUNT_, DEADLETTER_JOB_COUNT_, VAR_COUNT_, ID_LINK_COUNT_, :taskId")
                .append(" from act_ru_execution")
                 .append(" where PROC_INST_ID_ = :proInstanceId ");

        StringBuilder backup_hi_varinst = new StringBuilder(   "insert into backup_hi_varinst(ID_, PROC_INST_ID_, EXECUTION_ID_, TASK_ID_, NAME_, VAR_TYPE_, REV_, BYTEARRAY_ID_, DOUBLE_,")
                 .append("   LONG_, TEXT_, TEXT2_, CREATE_TIME_, LAST_UPDATED_TIME_, BACKUP_TASK_ID_)")
                 .append(" select ID_, PROC_INST_ID_, EXECUTION_ID_, TASK_ID_, NAME_, VAR_TYPE_, REV_, BYTEARRAY_ID_, DOUBLE_,")
                 .append("   LONG_, TEXT_, TEXT2_, CREATE_TIME_, LAST_UPDATED_TIME_, :taskId")
                 .append(" from act_hi_varinst")
                 .append(" where PROC_INST_ID_ = :proInstanceId ");
        StringBuilder backup_hi_taskinst = new StringBuilder(  "insert into backup_hi_taskinst(ID_, PROC_DEF_ID_, TASK_DEF_KEY_, PROC_INST_ID_, EXECUTION_ID_, NAME_, PARENT_TASK_ID_, DESCRIPTION_,")
                .append("  OWNER_, ASSIGNEE_, START_TIME_, CLAIM_TIME_, END_TIME_, DURATION_, DELETE_REASON_, PRIORITY_, DUE_DATE_, FORM_KEY_, CATEGORY_,")
                .append("  TENANT_ID_, BACKUP_TASK_ID_)")
                .append(" select ID_, PROC_DEF_ID_, TASK_DEF_KEY_, PROC_INST_ID_, EXECUTION_ID_, NAME_, PARENT_TASK_ID_, DESCRIPTION_,")
                .append("   OWNER_, ASSIGNEE_, START_TIME_, CLAIM_TIME_, END_TIME_, DURATION_, DELETE_REASON_, PRIORITY_, DUE_DATE_, FORM_KEY_, CATEGORY_,")
                .append("   TENANT_ID_, :taskId")
                .append(" from act_hi_taskinst")
                .append(" where PROC_INST_ID_ = :proInstanceId");
        StringBuilder backup_ru_variable = new StringBuilder(     "insert into backup_ru_variable(ID_, REV_, TYPE_, NAME_, EXECUTION_ID_, PROC_INST_ID_, TASK_ID_, BYTEARRAY_ID_, DOUBLE_,")
                .append("  LONG_, TEXT_, TEXT2_, BACKUP_TASK_ID_)")
                .append(" select ID_, REV_, TYPE_, NAME_, EXECUTION_ID_, PROC_INST_ID_, TASK_ID_, BYTEARRAY_ID_, DOUBLE_,")
                .append("   LONG_, TEXT_, TEXT2_, :taskId")
                .append(" from act_ru_variable where PROC_INST_ID_ = :proInstanceId");
        StringBuilder backup_ru_task = new StringBuilder("insert into backup_ru_task(ID_, REV_, EXECUTION_ID_, PROC_INST_ID_, PROC_DEF_ID_, NAME_, PARENT_TASK_ID_, DESCRIPTION_,")
                    .append(" TASK_DEF_KEY_, OWNER_, ASSIGNEE_, DELEGATION_, PRIORITY_, CREATE_TIME_, DUE_DATE_, CATEGORY_, SUSPENSION_STATE_, TENANT_ID_,")
                    .append("        FORM_KEY_, CLAIM_TIME_, BACKUP_TASK_ID_)")
                    .append(" select ID_, REV_, EXECUTION_ID_, PROC_INST_ID_, PROC_DEF_ID_, NAME_, PARENT_TASK_ID_, DESCRIPTION_,")
                    .append("        TASK_DEF_KEY_, OWNER_, ASSIGNEE_, DELEGATION_, PRIORITY_, CREATE_TIME_, DUE_DATE_, CATEGORY_, SUSPENSION_STATE_, TENANT_ID_,")
                    .append("        FORM_KEY_, CLAIM_TIME_, :taskId")
                    .append(" from act_ru_task where PROC_INST_ID_ = :proInstanceId");
        /*备份流程数据*/
        List<String> backupSqlList = Arrays.asList(
                backup_hi_actinst.toString(),
                backup_ru_execution.toString(),
                backup_hi_varinst.toString(),
                backup_hi_taskinst.toString(),
                backup_ru_variable.toString(),
                backup_ru_task.toString()
        );
        parms.clear();
        parms.put("taskId",taskId);
        parms.put("proInstanceId",proInstanceId);
        for (String sql : backupSqlList) {
            execute(sql,parms);
        }

    }
    public void deleteBackupByProcInstId(String processInstanceId){
        List<String> deleteBackupSql = Arrays.asList(
                "delete from backup_taskIds where PROC_INST_ID_ = :proInstanceId",
                "delete from backup_ru_identitylink where PROC_INST_ID_ = :proInstanceId ",
                "delete from backup_hi_identitylink where PROC_INST_ID_ = :proInstanceId ",
                "delete from backup_ru_execution where PROC_INST_ID_ = :proInstanceId ",
                "delete from backup_hi_varinst where PROC_INST_ID_ = :proInstanceId ",
                "delete from backup_hi_taskinst where PROC_INST_ID_ = :proInstanceId ",
                "delete from backup_hi_actinst where PROC_INST_ID_ = :proInstanceId",
                "delete from backup_ru_variable where PROC_INST_ID_ = :proInstanceId",
                "delete from backup_ru_task where PROC_INST_ID_ = :proInstanceId "
        );
        Map parms = new HashMap();
        parms.put("proInstanceId",processInstanceId);
        for (String sql : deleteBackupSql) {
            execute(sql,parms);
        }

    }
    /**
     * 流程撤回
     * @param taskId
     */
    public void withdrawTask(String taskId){
        try {

            HistoricTaskInstance taskInstance = processEngine.getHistoryService().createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
            if(taskInstance==null){
                throw new CustomRuntimeException("任务不存在！");
            }
            String proInstanceId = taskInstance.getProcessInstanceId();
            Map parms = new HashMap();
            parms.put("taskId",taskId);
            String validateSql = "SELECT * from backup_ru_task where BACKUP_TASK_ID_ = :taskId";
            Query query = entityManager.createNativeQuery(validateSql);
            SqlUtil.setQueryParams(parms,query);
            List resultList = query.getResultList();
            if(CollectionUtils.isEmpty(resultList)){
                throw new CustomRuntimeException("任务【"+taskId+"】不能撤回！");
            }
            WaitDone waitDone = waitDoneService.getById(taskId);
            if(waitDone==null){
                throw new CustomRuntimeException("该任务不存在，无法撤回");
            }
            boolean processEnd = workflowService.isProcessEnd(waitDone.getProcessInstanceId());
            if(processEnd){
                throw new CustomRuntimeException("流程未启动或已执行完成，无法撤回");
            }
            HistoricTaskInstance historicTaskInstance = processEngine.getHistoryService().createHistoricTaskInstanceQuery().taskAssignee(BizUtil.getUserId()).taskId(taskId).singleResult();
            if(historicTaskInstance==null){
                throw new CustomRuntimeException("非您任务，无法撤回！");
            }
            /**
             * 判断下一步任务是否已经完成
             */
            List<WaitDone> waitDones = waitDoneService.findByParentId(taskId);
            if(CollectionUtils.isEmpty(waitDones)){
                throw new CustomRuntimeException("该任务不能撤回！");
            }
            for (WaitDone done : waitDones) {
                if(done.getStatus()==1){
                    throw new CustomRuntimeException("该任务不能撤回！");
                }
            }
            //当前任务
            for (WaitDone done : waitDones) {
                Task task = processEngine.getTaskService().createTaskQuery().taskId(done.getId()).singleResult();
                waitDoneService.removeById(task.getId());
                waitDoneUserService.deleteByWaitDoneId(task.getId());
                parms.clear();
                parms.put("taskId",task.getId());
                //删除当前处理人的sql
                execute("delete from act_hi_identitylink where TASK_ID_ = :taskId",parms);
                execute("delete from act_ru_identitylink where TASK_ID_ = :taskId",parms);
            }
            //待办撤回
            WaitDone curWaitDone = waitDoneService.getById(taskId);
            curWaitDone.setDealTime(null);
            curWaitDone.setDealUserId(null);
            curWaitDone.setDealUserName(null);
            curWaitDone.setStatus(0);
            curWaitDone.setResult(null);
            curWaitDone.setOpinion(null);
            waitDoneService.updateById(curWaitDone);


            //设置外键不检验
            String setSql = "SET @@foreign_key_checks = 0";
            execute(setSql,null);

            //第一步，根据流程实例删除当前流程表数据
            List<String> deleteActSql = Arrays.asList(
                    "delete from act_ru_execution where PROC_INST_ID_ = :proInstanceId",
                    "delete from act_hi_varinst where PROC_INST_ID_ = :proInstanceId",
                    "delete from act_hi_taskinst where PROC_INST_ID_ = :proInstanceId",
                    "delete from act_hi_actinst where PROC_INST_ID_ = :proInstanceId",
                    "delete from act_ru_variable where PROC_INST_ID_ = :proInstanceId",
                    "delete from act_ru_task where PROC_INST_ID_ = :proInstanceId"
            );
            parms.clear();
            parms.put("proInstanceId",proInstanceId);
            for (String sql : deleteActSql) {
                execute(sql,parms);
            }

            //删除处理人的sql
            parms.clear();
            parms.put("taskId",taskId);
            execute("delete from act_ru_identitylink where TASK_ID_ = :taskId",parms);
            execute("delete from act_hi_identitylink where TASK_ID_ = :taskId",parms);


            //第二步:还原备份表数据至流程表
            StringBuilder backup_ru_identitylink = new StringBuilder("insert into act_ru_identitylink(ID_, REV_, GROUP_ID_, TYPE_, USER_ID_, TASK_ID_," )
                    .append("  PROC_INST_ID_, PROC_DEF_ID_)")
                    .append(" select ID_, REV_, GROUP_ID_, TYPE_, USER_ID_, TASK_ID_, PROC_INST_ID_, PROC_DEF_ID_")
                    .append(" from backup_ru_identitylink where BACKUP_TASK_ID_ = :taskId");
            StringBuilder backup_hi_identitylink = new StringBuilder(   "insert into act_hi_identitylink(ID_, GROUP_ID_, TYPE_, USER_ID_, TASK_ID_, PROC_INST_ID_)")
                    .append(" select ID_, GROUP_ID_, TYPE_, USER_ID_, TASK_ID_, PROC_INST_ID_")
                    .append(" from backup_hi_identitylink where BACKUP_TASK_ID_ = :taskId");
            StringBuilder backup_hi_actinst =new StringBuilder( "insert into act_hi_actinst(ID_, PROC_DEF_ID_, PROC_INST_ID_, EXECUTION_ID_,")
                    .append("  ACT_ID_, TASK_ID_, CALL_PROC_INST_ID_, ACT_NAME_,")
                    .append(" ACT_TYPE_, ASSIGNEE_, START_TIME_, END_TIME_, DURATION_, DELETE_REASON_, TENANT_ID_)")
                    .append(" select ID_, PROC_DEF_ID_, PROC_INST_ID_, EXECUTION_ID_, ACT_ID_, TASK_ID_, CALL_PROC_INST_ID_, ACT_NAME_,")
                    .append("  ACT_TYPE_, ASSIGNEE_, START_TIME_, END_TIME_, DURATION_, DELETE_REASON_, TENANT_ID_")
                    .append(" from backup_hi_actinst where BACKUP_TASK_ID_ = :taskId");
            StringBuilder backup_ru_execution = new StringBuilder(  "insert into act_ru_execution(ID_, REV_, PROC_INST_ID_, BUSINESS_KEY_,")
                    .append("  PARENT_ID_, PROC_DEF_ID_, SUPER_EXEC_,")
                    .append("         ROOT_PROC_INST_ID_, ACT_ID_, IS_ACTIVE_, IS_CONCURRENT_, IS_SCOPE_, IS_EVENT_SCOPE_, IS_MI_ROOT_, SUSPENSION_STATE_,")
                    .append("         CACHED_ENT_STATE_, TENANT_ID_, NAME_, START_TIME_, START_USER_ID_, LOCK_TIME_, IS_COUNT_ENABLED_, EVT_SUBSCR_COUNT_,")
                    .append("         TASK_COUNT_, JOB_COUNT_, TIMER_JOB_COUNT_, SUSP_JOB_COUNT_, DEADLETTER_JOB_COUNT_, VAR_COUNT_, ID_LINK_COUNT_)")
                    .append(" select ID_, REV_, PROC_INST_ID_, BUSINESS_KEY_, PARENT_ID_, PROC_DEF_ID_, SUPER_EXEC_,")
                    .append("         ROOT_PROC_INST_ID_, ACT_ID_, IS_ACTIVE_, IS_CONCURRENT_, IS_SCOPE_, IS_EVENT_SCOPE_, IS_MI_ROOT_, SUSPENSION_STATE_,")
                    .append("         CACHED_ENT_STATE_, TENANT_ID_, NAME_, START_TIME_, START_USER_ID_, LOCK_TIME_, IS_COUNT_ENABLED_, EVT_SUBSCR_COUNT_,")
                    .append("         TASK_COUNT_, JOB_COUNT_, TIMER_JOB_COUNT_, SUSP_JOB_COUNT_, DEADLETTER_JOB_COUNT_, VAR_COUNT_, ID_LINK_COUNT_")
                    .append(" from backup_ru_execution")
                    .append(" where BACKUP_TASK_ID_ = :taskId");

            StringBuilder backup_hi_varinst = new StringBuilder(   "insert into act_hi_varinst(ID_, PROC_INST_ID_, EXECUTION_ID_, TASK_ID_, NAME_, VAR_TYPE_, REV_, BYTEARRAY_ID_, DOUBLE_,")
                    .append("   LONG_, TEXT_, TEXT2_, CREATE_TIME_, LAST_UPDATED_TIME_)")
                    .append(" select ID_, PROC_INST_ID_, EXECUTION_ID_, TASK_ID_, NAME_, VAR_TYPE_, REV_, BYTEARRAY_ID_, DOUBLE_,")
                    .append("   LONG_, TEXT_, TEXT2_, CREATE_TIME_, LAST_UPDATED_TIME_")
                    .append(" from backup_hi_varinst")
                    .append(" where BACKUP_TASK_ID_ = :taskId");
            StringBuilder backup_hi_taskinst = new StringBuilder(  "insert into act_hi_taskinst(ID_, PROC_DEF_ID_, TASK_DEF_KEY_, PROC_INST_ID_, EXECUTION_ID_, NAME_, PARENT_TASK_ID_, DESCRIPTION_,")
                    .append("  OWNER_, ASSIGNEE_, START_TIME_, CLAIM_TIME_, END_TIME_, DURATION_, DELETE_REASON_, PRIORITY_, DUE_DATE_, FORM_KEY_, CATEGORY_,")
                    .append("  TENANT_ID_)")
                    .append(" select ID_, PROC_DEF_ID_, TASK_DEF_KEY_, PROC_INST_ID_, EXECUTION_ID_, NAME_, PARENT_TASK_ID_, DESCRIPTION_,")
                    .append("   OWNER_, ASSIGNEE_, START_TIME_, CLAIM_TIME_, END_TIME_, DURATION_, DELETE_REASON_, PRIORITY_, DUE_DATE_, FORM_KEY_, CATEGORY_,")
                    .append("   TENANT_ID_")
                    .append(" from backup_hi_taskinst")
                    .append(" where BACKUP_TASK_ID_ = :taskId");

            StringBuilder backup_ru_variable = new StringBuilder(     "insert into act_ru_variable(ID_, REV_, TYPE_, NAME_, EXECUTION_ID_, PROC_INST_ID_, TASK_ID_, BYTEARRAY_ID_, DOUBLE_,")
                    .append("  LONG_, TEXT_, TEXT2_)")
                    .append(" select ID_, REV_, TYPE_, NAME_, EXECUTION_ID_, PROC_INST_ID_, TASK_ID_, BYTEARRAY_ID_, DOUBLE_,")
                    .append("   LONG_, TEXT_, TEXT2_")
                    .append(" from backup_ru_variable where BACKUP_TASK_ID_ = :taskId");
            StringBuilder backup_ru_task = new StringBuilder("insert into act_ru_task(ID_, REV_, EXECUTION_ID_, PROC_INST_ID_, PROC_DEF_ID_, NAME_, PARENT_TASK_ID_, DESCRIPTION_,")
                    .append(" TASK_DEF_KEY_, OWNER_, ASSIGNEE_, DELEGATION_, PRIORITY_, CREATE_TIME_, DUE_DATE_, CATEGORY_, SUSPENSION_STATE_, TENANT_ID_,")
                    .append("        FORM_KEY_, CLAIM_TIME_)")
                    .append(" select ID_, REV_, EXECUTION_ID_, PROC_INST_ID_, PROC_DEF_ID_, NAME_, PARENT_TASK_ID_, DESCRIPTION_,")
                    .append("        TASK_DEF_KEY_, OWNER_, ASSIGNEE_, DELEGATION_, PRIORITY_, CREATE_TIME_, DUE_DATE_, CATEGORY_, SUSPENSION_STATE_, TENANT_ID_,")
                    .append("        FORM_KEY_, CLAIM_TIME_")
                    .append(" from backup_ru_task where BACKUP_TASK_ID_ = :taskId");
            /*备份流程数据*/
            List<String> backupSqlList = Arrays.asList(
                    backup_hi_actinst.toString(),
                    backup_ru_identitylink.toString(),
                    backup_ru_execution.toString(),
                    backup_hi_varinst.toString(),
                    backup_hi_taskinst.toString(),
                    backup_hi_identitylink.toString(),
                    backup_ru_variable.toString(),
                    backup_ru_task.toString()
            );
            parms.clear();
            parms.put("taskId",taskId);
            for (String sql : backupSqlList) {
                execute(sql,parms);
            }



            //第三步，删除流程备份表数据
            List<String> deleteBackupSql = Arrays.asList(
                    "delete from backup_taskIds where PROC_INST_ID_ = :proInstanceId and  BACKUP_TASK_ID_ >= :taskId",
                    "delete from backup_ru_identitylink where PROC_INST_ID_ = :proInstanceId and  BACKUP_TASK_ID_ >= :taskId",
                    "delete from backup_hi_identitylink where PROC_INST_ID_ = :proInstanceId and  BACKUP_TASK_ID_ >= :taskId",
                    "delete from backup_ru_execution where PROC_INST_ID_ = :proInstanceId and  BACKUP_TASK_ID_ >= :taskId",
                    "delete from backup_hi_varinst where PROC_INST_ID_ = :proInstanceId and  BACKUP_TASK_ID_ >= :taskId",
                    "delete from backup_hi_taskinst where PROC_INST_ID_ = :proInstanceId and  BACKUP_TASK_ID_ >= :taskId",
                    "delete from backup_hi_actinst where PROC_INST_ID_ = :proInstanceId and  BACKUP_TASK_ID_ >= :taskId",
                    "delete from backup_ru_variable where PROC_INST_ID_ = :proInstanceId and  BACKUP_TASK_ID_ >= :taskId",
                    "delete from backup_ru_task where PROC_INST_ID_ = :proInstanceId and  BACKUP_TASK_ID_ >= :taskId"
            );
            parms.clear();
            parms.put("taskId",taskId);
            parms.put("proInstanceId",proInstanceId);
            for (String sql : deleteBackupSql) {
                execute(sql,parms);
            }

            //第四步，更新上一步任务的备份状态为可撤回
            String updateWithdrawStatus = " update backup_taskIds inner join (" +
                    "      select max(BACKUP_TASK_ID_) as lastTaskId, PROC_INST_ID_ from backup_taskIds where PROC_INST_ID_ = :proInstanceId" +
                    "    ) temp on backup_taskIds.PROC_INST_ID_ = temp.PROC_INST_ID_ and backup_taskIds.BACKUP_TASK_ID_ = temp.lastTaskId" +
                    "    set backup_taskIds.CAN_WITHDRAW = 1";
            parms.clear();
            parms.put("proInstanceId",proInstanceId);
            execute(updateWithdrawStatus,parms);
        }finally {
            //设置外键检验
            String setSql = "SET @@foreign_key_checks = 1";
            execute(setSql,null);
        }

    }

    /**
     * 任务是否能撤回
     */
    public boolean isWithdrawTask(String taskId) {
        StringBuffer sql = new StringBuffer("select *  from backup_taskids btids where btids.BACKUP_TASK_ID_ = ? and btids.CAN_WITHDRAW = 1 ");

        Query query = entityManager.createNativeQuery(sql.toString());
        query.setParameter(1, taskId);
        List resultList = query.getResultList();
        return !CollectionUtils.isEmpty(resultList);
    }
}